// import { lib, register } from "@aotoo/react-cell";
import { lib, register } from "./cell";

// let [checked, setChecked] = React.useState([])
let myChecked = {};
let setByEvent = false; // 是否通过事件改变值
export function Checkbox(props) {
  /**
   * { name: 'xxx', value: '1', values: [
   *     '1',
   *     '2',
   *     ['3', {readonly: true, title: 'xxx'}]
   *   ]
   *  }
   */
  let store = props.store;  // store === elementContext 实际上是该input元素的上下文环境
  let is = props.is || "checkbox"; // checkbox  radiobox
  let keywords = [
    "id",
    "name",
    "values",
    "value",
    "inputType",
    "type",
    "className",
    "style"
  ];
  let attributes = {};
  let other = {};
  let eles = [];

  function partfix(param, cls) {
    if (React.isValidElement(param)) return param;
    else if (lib.isString(param)) {
      return <span className={cls}>{param}</span>;
    }
    return null;
  }

  Object.keys(props).forEach((ky) => {
    if (keywords.indexOf(ky) > -1) {
      attributes[ky] = props[ky];
    } else {
      other[ky] = props[ky];
    }
  });

  let $inputType = attributes.inputType || attributes.type || "checkbox";
  delete attributes.inputType;
  delete attributes.type;
  let $className = attributes.className === 'input' ? 'checkbox-group' : attributes.className;
  let $id = attributes.id || "ckbox";
  let $name = attributes.name || $id;
  let $value = attributes.value;
  let $values = attributes.values || [];
  let checked = myChecked[$name];

  if (!$values.length) {
    console.warn(`必须指定values属性，如values:['1', '2', '3']`);
    return null;
  }

  if (!checked) {
    checked = [];
    myChecked[$name] = checked;
  }

  function hasChecked(val) {
    let index = -1;
    let target = { index: -1, value: null };
    checked.forEach((v, ii) => {
      if (lib.isString(v) && v === val) {
        index = ii;
        target = {
          index: ii,
          value: [v, {}]
        };
      } else if (lib.isArray(v)) {
        let $v = v[0];
        if ($v === val) {
          index = ii;
          target = {
            index: ii,
            value: v
          };
        }
      }
    });
    return index > -1 ? target : false;
  }

  function setMyChecked(val, opts) {
    if ($inputType === "radio") {
      if (opts) {
        checked = [[val, opts]];
      } else {
        checked = [val];
      }
    } else {
      if (hasChecked(val)) {
        if (setByEvent) {
          let index = checked.findIndex((v) => v === val);
          checked.splice(index, 1);
        }
      } else {
        if (opts) {
          checked.push([val, opts]);
        } else {
          checked.push(val);
        }
      }
    }
    setByEvent = false;
    myChecked[$name] = checked;
  }

  function genChecked($val) {
    if (lib.isString($val)) {
      setMyChecked($val);
    } else if (lib.isArray($val)) {
      checked = [];
      $val.forEach((v) => {
        if (lib.isString(v)) setMyChecked(v);
        else if (lib.isArray(v)) {
          if (lib.isString(v[0])) {
            if (lib.isPlainObject(v[1])) {
              setMyChecked(v[0], v[1]);
            } else {
              setMyChecked(v[0]);
            }
          }
        }
      });
    }
  }

  genChecked($value);

  store.getValue = function () {
    let result = [];
    let cked = myChecked[$name];
    cked.forEach((item) => {
      if (lib.isString(item)) {
        result.push(item);
      } else {
        if (lib.isArray(item)) {
          const param = item[1] || {};
          if (param.checked) result.push(item[0]);
        }
      }
    });
    return result;
  };

  if (is === "checkbox") {
    let allChecked = [];
    store.selectAll = function (status) {
      let checkedIt = status === undefined || status === true ? true : false;
      $values.forEach((item) => {
        if (lib.isString(item)) item = [item, { checked: checkedIt }];
        let val = item[0];
        let obj = { checked: checkedIt };
        allChecked.push([val, obj]);
      });
      checked = [];
      if (!checkedIt) {
        allChecked = [];
        myChecked[$name] = [];
      }
      store.setValue(allChecked);
    };
  }

  const optionsClass = []
  $values.forEach((item, ii) => {
    if (lib.isString(item)) item = [item, {}];
    let autoId = $id + "-" + ii;
    let val = item[0];
    let obj = item[1];
    let res = hasChecked(val);
    if (res) {
      let idx = res.index;
      let vv = res.value;
      let opts = vv[1];
      obj.checked = true;
      obj = Object.assign({}, obj, opts);
    } else {
      obj.checked = false;
      if (lib.isArray($value)) {
        $value.forEach((it) => {
          if (lib.isArray(it) && it[0] === val) {
            obj = Object.assign({}, obj, it[1]);
          }
        });
      }
    }

    let title = obj.title; // delete obj.title;
    let desc = obj.desc; // delete obj.desc
    let otherAttributes = Object.assign({}, obj, other);
    let customOnChange = obj.onChange;

    delete otherAttributes.title;
    delete otherAttributes.desc;
    if (otherAttributes.store || otherAttributes.parent) {
      delete otherAttributes.store;
      delete otherAttributes.parent;
    }

    let oldOnChange = otherAttributes.onChange;
    let [preChangeCallback, nextChangeCallback, parentStore] =
      oldOnChange &&
      oldOnChange(function (e, param, inst) {
        setByEvent = true;
        let readOnly = e.target.readOnly;
        let disabled = e.target.disabled;
        if (readOnly || disabled) return;

        if (lib.isString(preChangeCallback)) {
          if (lib.isFunction(store[preChangeCallback])) {
            preChangeCallback = store[preChangeCallback];
          }
        }

        if (preChangeCallback.name !== "innerOnChange") {
          // 非内部自动指定的onChange事件
          if (preChangeCallback.call(inst, e, param, inst)) {
            inst.save(e);
          }
        } else {
          if (lib.isString(customOnChange)) {
            const obj = lib.urlTOquery(customOnChange);
            const query = obj.query;
            const funName = obj.url;
            if (lib.isFunction(parentStore[funName])) {
              if (parentStore[funName].call(inst, e, query, inst)) {
                inst.save(e);
              }
            }
          } else if (lib.isFunction(customOnChange)) {
            if (customOnChange.call(inst, e, param, inst)) {
              inst.save(e);
            }
          } else {
            preChangeCallback.call(inst, e, param, inst);
          }
        }
      });
    otherAttributes.onChange =
      nextChangeCallback ||
      function (e, param, inst) {
        setByEvent = true;
        let readOnly = e.target.readOnly;
        let disabled = e.target.disabled;
        if (readOnly || disabled) return;
        inst.save(e);
      };
      
    optionsClass.push(otherAttributes.className)
    delete otherAttributes.className
    eles.push([
      partfix(title, is+"-title"),
      <input
        type={$inputType}
        id={autoId}
        name={$name}
        value={val}
        {...otherAttributes}
      />,
      partfix(desc, is+"-descript"),
      autoId,
      $name,
      val
    ]);
  });

  let ckBox = eles.map((cbitem, ii) => {
    let title = cbitem[0];
    let input = cbitem[1];
    let desc = cbitem[2];
    let $id = cbitem[3];
    let $name = cbitem[4];
    let $val = cbitem[5];
    let $key = $id + "-" + ii;
    return (
      <label htmlFor={$id} key={$key} className={(optionsClass[ii]||null)}>
        {title}
        {input}
        {desc}
      </label>
    );
  });
  return <div className={$className || "checkbox-group"}>{ckBox}</div>;
}

register("Checkbox", ["checkbox"], Checkbox);
